{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# How to add tools to chatbots\n",
        "\n",
        ":::info Prerequisites\n",
        "\n",
        "This guide assumes familiarity with the following concepts:\n",
        "\n",
        "- [Chatbots](/docs/concepts/messages)\n",
        "- [Agents](https://langchain-ai.github.io/langgraphjs/tutorials/multi_agent/agent_supervisor/)\n",
        "- [Chat history](/docs/concepts/chat_history)\n",
        "\n",
        ":::\n",
        "\n",
        "This section will cover how to create conversational agents: chatbots that can interact with other systems and APIs using tools.\n",
        "\n",
        ":::note\n",
        "\n",
        "This how-to guide previously built a chatbot using [RunnableWithMessageHistory](https://api.js.langchain.com/classes/_langchain_core.runnables.RunnableWithMessageHistory.html). You can access this version of the tutorial in the [v0.2 docs](https://js.langchain.com/v0.2/docs/how_to/chatbots_tools/).\n",
        "\n",
        "The LangGraph implementation offers a number of advantages over `RunnableWithMessageHistory`, including the ability to persist arbitrary components of an application's state (instead of only messages).\n",
        "\n",
        ":::\n",
        "\n",
        "## Setup\n",
        "\n",
        "For this guide, we'll be using a [tool calling agent](https://langchain-ai.github.io/langgraphjs/concepts/agentic_concepts/#tool-calling-agent) with a single tool for searching the web. The default will be powered by [Tavily](/docs/integrations/tools/tavily_search), but you can switch it out for any similar tool. The rest of this section will assume you're using Tavily.\n",
        "\n",
        "You'll need to [sign up for an account](https://tavily.com/) on the Tavily website, and install the following packages:\n",
        "\n",
        "```{=mdx}\n",
        "import Npm2Yarn from \"@theme/Npm2Yarn\";\n",
        "\n",
        "<Npm2Yarn>\n",
        "  @langchain/core @langchain/langgraph @langchain/community\n",
        "</Npm2Yarn>\n",
        "```\n",
        "\n",
        "Let’s also set up a chat model that we’ll use for the below examples.\n",
        "\n",
        "```{=mdx}\n",
        "import ChatModelTabs from \"@theme/ChatModelTabs\";\n",
        "\n",
        "<ChatModelTabs customVarName=\"llm\" />\n",
        "```\n",
        "\n",
        "```typescript\n",
        "process.env.TAVILY_API_KEY = \"YOUR_API_KEY\";\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Creating an agent\n",
        "\n",
        "Our end goal is to create an agent that can respond conversationally to user questions while looking up information as needed.\n",
        "\n",
        "First, let's initialize Tavily and an OpenAI chat model capable of tool calling:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [],
      "source": [
        "// @lc-docs-hide-cell\n",
        "\n",
        "import { ChatOpenAI } from \"@langchain/openai\";\n",
        "\n",
        "const llm = new ChatOpenAI({\n",
        "  model: \"gpt-4o\",\n",
        "  temperature: 0,\n",
        "});"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [],
      "source": [
        "import { TavilySearchResults } from \"@langchain/community/tools/tavily_search\";\n",
        "\n",
        "const tools = [\n",
        "  new TavilySearchResults({\n",
        "    maxResults: 1,\n",
        "  }),\n",
        "];"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To make our agent conversational, we can also specify a prompt. Here's an example:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [],
      "source": [
        "import {\n",
        "  ChatPromptTemplate,\n",
        "} from \"@langchain/core/prompts\";\n",
        "\n",
        "// Adapted from https://smith.langchain.com/hub/jacob/tool-calling-agent\n",
        "const prompt = ChatPromptTemplate.fromMessages([\n",
        "  [\n",
        "    \"system\",\n",
        "    \"You are a helpful assistant. You may not need to use tools for every query - the user may just want to chat!\",\n",
        "  ],\n",
        "]);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Great! Now let's assemble our agent using LangGraph's prebuilt [createReactAgent](https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html), which allows you to create a [tool-calling agent](https://langchain-ai.github.io/langgraphjs/concepts/agentic_concepts/#tool-calling-agent):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {},
      "outputs": [],
      "source": [
        "import { createReactAgent } from \"@langchain/langgraph/prebuilt\"\n",
        "\n",
        "// messageModifier allows you to preprocess the inputs to the model inside ReAct agent\n",
        "// in this case, since we're passing a prompt string, we'll just always add a SystemMessage\n",
        "// with this prompt string before any other messages sent to the model\n",
        "const agent = createReactAgent({ llm, tools, messageModifier: prompt })"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Running the agent\n",
        "\n",
        "Now that we've set up our agent, let's try interacting with it! It can handle both trivial queries that require no lookup:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{\n",
            "  messages: [\n",
            "    HumanMessage {\n",
            "      \"id\": \"8c5fa465-e8d8-472a-9434-f574bf74537f\",\n",
            "      \"content\": \"I'm Nemo!\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {}\n",
            "    },\n",
            "    AIMessage {\n",
            "      \"id\": \"chatcmpl-ABTKLLriRcZin65zLAMB3WUf9Sg1t\",\n",
            "      \"content\": \"How can I assist you today?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {\n",
            "        \"tokenUsage\": {\n",
            "          \"completionTokens\": 8,\n",
            "          \"promptTokens\": 93,\n",
            "          \"totalTokens\": 101\n",
            "        },\n",
            "        \"finish_reason\": \"stop\",\n",
            "        \"system_fingerprint\": \"fp_3537616b13\"\n",
            "      },\n",
            "      \"tool_calls\": [],\n",
            "      \"invalid_tool_calls\": [],\n",
            "      \"usage_metadata\": {\n",
            "        \"input_tokens\": 93,\n",
            "        \"output_tokens\": 8,\n",
            "        \"total_tokens\": 101\n",
            "      }\n",
            "    }\n",
            "  ]\n",
            "}\n"
          ]
        }
      ],
      "source": [
        "await agent.invoke({ messages: [{ role: \"user\", content: \"I'm Nemo!\" }]})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Or, it can use of the passed search tool to get up to date information if needed:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{\n",
            "  messages: [\n",
            "    HumanMessage {\n",
            "      \"id\": \"65c315b6-2433-4cb1-97c7-b60b5546f518\",\n",
            "      \"content\": \"What is the current conservation status of the Great Barrier Reef?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {}\n",
            "    },\n",
            "    AIMessage {\n",
            "      \"id\": \"chatcmpl-ABTKLQn1e4axRhqIhpKMyzWWTGauO\",\n",
            "      \"content\": \"How can I assist you today?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {\n",
            "        \"tokenUsage\": {\n",
            "          \"completionTokens\": 8,\n",
            "          \"promptTokens\": 93,\n",
            "          \"totalTokens\": 101\n",
            "        },\n",
            "        \"finish_reason\": \"stop\",\n",
            "        \"system_fingerprint\": \"fp_3537616b13\"\n",
            "      },\n",
            "      \"tool_calls\": [],\n",
            "      \"invalid_tool_calls\": [],\n",
            "      \"usage_metadata\": {\n",
            "        \"input_tokens\": 93,\n",
            "        \"output_tokens\": 8,\n",
            "        \"total_tokens\": 101\n",
            "      }\n",
            "    }\n",
            "  ]\n",
            "}\n"
          ]
        }
      ],
      "source": [
        "await agent.invoke({ messages: [{ role: \"user\", content: \"What is the current conservation status of the Great Barrier Reef?\" }]})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Conversational responses\n",
        "\n",
        "Because our prompt contains a placeholder for chat history messages, our agent can also take previous interactions into account and respond conversationally like a standard chatbot:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{\n",
            "  messages: [\n",
            "    HumanMessage {\n",
            "      \"id\": \"6433afc5-31bd-44b3-b34c-f11647e1677d\",\n",
            "      \"content\": \"I'm Nemo!\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {}\n",
            "    },\n",
            "    HumanMessage {\n",
            "      \"id\": \"f163b5f1-ea29-4d7a-9965-7c7c563d9cea\",\n",
            "      \"content\": \"Hello Nemo! How can I assist you today?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {}\n",
            "    },\n",
            "    HumanMessage {\n",
            "      \"id\": \"382c3354-d02b-4888-98d8-44d75d045044\",\n",
            "      \"content\": \"What is my name?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {}\n",
            "    },\n",
            "    AIMessage {\n",
            "      \"id\": \"chatcmpl-ABTKMKu7ThZDZW09yMIPTq2N723Cj\",\n",
            "      \"content\": \"How can I assist you today?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {\n",
            "        \"tokenUsage\": {\n",
            "          \"completionTokens\": 8,\n",
            "          \"promptTokens\": 93,\n",
            "          \"totalTokens\": 101\n",
            "        },\n",
            "        \"finish_reason\": \"stop\",\n",
            "        \"system_fingerprint\": \"fp_e375328146\"\n",
            "      },\n",
            "      \"tool_calls\": [],\n",
            "      \"invalid_tool_calls\": [],\n",
            "      \"usage_metadata\": {\n",
            "        \"input_tokens\": 93,\n",
            "        \"output_tokens\": 8,\n",
            "        \"total_tokens\": 101\n",
            "      }\n",
            "    }\n",
            "  ]\n",
            "}\n"
          ]
        }
      ],
      "source": [
        "await agent.invoke({\n",
        "  messages: [\n",
        "    { role: \"user\", content: \"I'm Nemo!\" },\n",
        "    { role: \"user\", content: \"Hello Nemo! How can I assist you today?\" },\n",
        "    { role: \"user\", content: \"What is my name?\" }\n",
        "  ]\n",
        "})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If preferred, you can also add memory to the LangGraph agent to manage the history of messages. Let's redeclare it this way:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {},
      "outputs": [],
      "source": [
        "import { MemorySaver } from \"@langchain/langgraph\"\n",
        "\n",
        "// highlight-start\n",
        "const memory = new MemorySaver()\n",
        "const agent2 = createReactAgent({ llm, tools, messageModifier: prompt, checkpointSaver: memory })\n",
        "// highlight-end"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{\n",
            "  messages: [\n",
            "    HumanMessage {\n",
            "      \"id\": \"a4a4f663-8192-4179-afcc-88d9d186aa80\",\n",
            "      \"content\": \"I'm Nemo!\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {}\n",
            "    },\n",
            "    AIMessage {\n",
            "      \"id\": \"chatcmpl-ABTKi4tBzOWMh3hgA46xXo7bJzb8r\",\n",
            "      \"content\": \"How can I assist you today?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {\n",
            "        \"tokenUsage\": {\n",
            "          \"completionTokens\": 8,\n",
            "          \"promptTokens\": 93,\n",
            "          \"totalTokens\": 101\n",
            "        },\n",
            "        \"finish_reason\": \"stop\",\n",
            "        \"system_fingerprint\": \"fp_e375328146\"\n",
            "      },\n",
            "      \"tool_calls\": [],\n",
            "      \"invalid_tool_calls\": [],\n",
            "      \"usage_metadata\": {\n",
            "        \"input_tokens\": 93,\n",
            "        \"output_tokens\": 8,\n",
            "        \"total_tokens\": 101\n",
            "      }\n",
            "    }\n",
            "  ]\n",
            "}\n"
          ]
        }
      ],
      "source": [
        "await agent2.invoke({ messages: [{ role: \"user\", content: \"I'm Nemo!\" }]}, { configurable: { thread_id: \"1\" } })"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "And then if we rerun our wrapped agent executor:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{\n",
            "  messages: [\n",
            "    HumanMessage {\n",
            "      \"id\": \"c5fd303c-eb49-41a0-868e-bc8c5aa02cf6\",\n",
            "      \"content\": \"I'm Nemo!\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {}\n",
            "    },\n",
            "    AIMessage {\n",
            "      \"id\": \"chatcmpl-ABTKi4tBzOWMh3hgA46xXo7bJzb8r\",\n",
            "      \"content\": \"How can I assist you today?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {\n",
            "        \"tokenUsage\": {\n",
            "          \"completionTokens\": 8,\n",
            "          \"promptTokens\": 93,\n",
            "          \"totalTokens\": 101\n",
            "        },\n",
            "        \"finish_reason\": \"stop\",\n",
            "        \"system_fingerprint\": \"fp_e375328146\"\n",
            "      },\n",
            "      \"tool_calls\": [],\n",
            "      \"invalid_tool_calls\": []\n",
            "    },\n",
            "    HumanMessage {\n",
            "      \"id\": \"635b17b9-2ec7-412f-bf45-85d0e9944430\",\n",
            "      \"content\": \"What is my name?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {}\n",
            "    },\n",
            "    AIMessage {\n",
            "      \"id\": \"chatcmpl-ABTKjBbmFlPb5t37aJ8p4NtoHb8YG\",\n",
            "      \"content\": \"How can I assist you today?\",\n",
            "      \"additional_kwargs\": {},\n",
            "      \"response_metadata\": {\n",
            "        \"tokenUsage\": {\n",
            "          \"completionTokens\": 8,\n",
            "          \"promptTokens\": 93,\n",
            "          \"totalTokens\": 101\n",
            "        },\n",
            "        \"finish_reason\": \"stop\",\n",
            "        \"system_fingerprint\": \"fp_e375328146\"\n",
            "      },\n",
            "      \"tool_calls\": [],\n",
            "      \"invalid_tool_calls\": [],\n",
            "      \"usage_metadata\": {\n",
            "        \"input_tokens\": 93,\n",
            "        \"output_tokens\": 8,\n",
            "        \"total_tokens\": 101\n",
            "      }\n",
            "    }\n",
            "  ]\n",
            "}\n"
          ]
        }
      ],
      "source": [
        "await agent2.invoke({ messages: [{ role: \"user\", content: \"What is my name?\" }]}, { configurable: { thread_id: \"1\" } })"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "This [LangSmith trace](https://smith.langchain.com/public/16cbcfa5-5ef1-4d4c-92c9-538a6e71f23d/r) shows what's going on under the hood.\n",
        "\n",
        "## Further reading\n",
        "\n",
        "For more on how to build agents, check these [LangGraph](https://langchain-ai.github.io/langgraphjs/) guides:\n",
        "\n",
        "* [agents conceptual guide](https://langchain-ai.github.io/langgraphjs/concepts/agentic_concepts/)\n",
        "* [agents tutorials](https://langchain-ai.github.io/langgraphjs/tutorials/multi_agent/multi_agent_collaboration/)\n",
        "* [createReactAgent](https://langchain-ai.github.io/langgraphjs/how-tos/create-react-agent/)\n",
        "\n",
        "For more on tool usage, you can also check out [this use case section](/docs/how_to#tools)."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Deno",
      "language": "typescript",
      "name": "deno"
    },
    "language_info": {
      "codemirror_mode": {
        "mode": "typescript",
        "name": "javascript",
        "typescript": true
      },
      "file_extension": ".ts",
      "mimetype": "text/typescript",
      "name": "typescript",
      "version": "3.7.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}
